/*******************************************************************************
 * Copyright 2007 Vidar Svansson
 *
 * This file is part of JAdapter.
 *
 * JAdapter is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JAdapter is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with JAdapter.  If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/


package org.jadapter.tests;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import junit.framework.TestCase;

import org.jadapter.Components;
import org.jadapter.tests.examples.CommaSeparated;
import org.jadapter.tests.examples.CommaSeparatedList;
import org.jadapter.tests.examples.CommaSeparatedMap;


public class BasicUsage extends TestCase {

    /******************* 
    
    // simple interface that is used to get a string representation of
    // a collection of strings.
    public interface CommaSeparated {
        String getCommaSeparated();
    }
    
    // an example of a adapter with context constructor 
    public class CommaSeparatedMap implements CommaSeparated {

        private Map<?,?> context;

        // JAdapter injects the context using this constructor
        public CommaSeparatedMap(Map<?,?> context) {
            this.context = context;
        }

        // implementation of the interface for the context
        public String getCommaSeparated() {
            if(context == null) 
                return "";      
            StringBuffer buffer = new StringBuffer();
            for(Object key : context.keySet()) 
                buffer.append(key + ":" + context.get(key) + ",");
            if(context.size() > 0)
                buffer.deleteCharAt(buffer.length() - 1);
            return buffer.toString();
        }              
    }
    
    *******************/
    
    
    public void testAdapterBasicUsage() throws Exception {
        // Before we test using JAdapter, we test the components
        
        // this is the context object that we want to adapt to some type    
        Map<String, String> map = new HashMap<String,String>(){{
            put("Foo", "foo");
            put("Bar", "bar");
        }};
        
        // this is our target, CommaSeparated is an interface
        CommaSeparated commas;
        
        // This is a simple adapter that implements CommaSeparated and
        // has a constructor accepting a single Map instance
        commas = new CommaSeparatedMap(map);
        assertEquals("Foo:foo,Bar:bar", commas.getCommaSeparated());
        
        
        // OK, lets do that with JAdapter
        
        // we are using the API directly here to register the adapter 
        // before we use it, normally this would be somewhere in the
        // initialization of the application, e.g. by using an IoC
        // framework.
        Components.register(
                CommaSeparated.class, // the provided type
                CommaSeparatedMap.class, // the adapter implementing above
                Map.class); // the type of the context objects
        
        // if you don't prefer to call a function with multiple parameters of
        // the same type, then you can pass a single JAdapter instance to register
            
        // now JAdapter knows that we can use CommaSeparatedMap when we need to
        // adapt Map -> CommaSeparated
        // so we simply ask the component registry to give us a CommaSeparated 
        // instance for the map object
        commas = Components.get(CommaSeparated.class, map);
        assertEquals("Foo:foo,Bar:bar", commas.getCommaSeparated());
        
    }    

    
    public void testUtilityBasicUsage() throws Exception {       
        // we can register factory classes
        // behind the schemes this is simply an adapter that adapts
        // List to null (i.e. it adapts any context).
        Components.register(List.class, LinkedList.class);
        
        // to obtain a fresh copy of the List interface, we use `create(Class)`
        List list = Components.create(List.class);
        assertEquals(0, list.size());
        assertTrue(list instanceof LinkedList);
        
        // we can also register singletons
        list.add(1);
        Components.register(List.class, list);
        
        list = Components.get(List.class);
        assertEquals(1, list.size());
        assertEquals(1, list.get(0));
             
        // context based utilities
        Components.register(List.class, new ArrayList(), String.class);
        list = Components.get(List.class, String.class);
        assertEquals(0, list.size());
        assertTrue(list instanceof ArrayList);   
        
        // we can still get the default instance
        List old = Components.get(List.class);
        assertTrue(old instanceof LinkedList);       
        
        // we can also create context-specific instances
        list.add(1); // mark object as used
        Components.register(List.class, ArrayList.class, String.class);
        list = Components.create(List.class, String.class);
        assertEquals(0, list.size());
        assertTrue(list instanceof ArrayList);       
                
    }
    
    
    /*********************************************/
    // test end here, below is just some drafts for example on the wiki
    
    public void saveCommaSeparated(final CommaSeparated cs) {
        String s = cs.getCommaSeparated();
        //writeFile(cs);
    }
    
    
    public void saveToDisk(final Object o) {
        CommaSeparated commas;
        if(o instanceof Map) {
            commas = new CommaSeparatedMap((Map)o);           
        } else if(o instanceof List) {
            commas = new CommaSeparatedList(){{setList((List)o);}};
        } else {
            throw new RuntimeException("unknown type: " + o.getClass());
        }
        saveCommaSeparated(commas);
    }
    
    public void saveToDisk2(final Object o) {
        CommaSeparated commas = Components.get(CommaSeparated.class, o);
        saveCommaSeparated(commas);
    }
    
    private static void registerComponents() {
        Components.register(
                CommaSeparated.class,    // the provided type
                CommaSeparatedMap.class, // the adapter implementing above
                Map.class);              // the type of the context objects        
    }
    
    public static void main(String [] args) {
        registerComponents();
        //init();       
    }    
    
    public void showXStream() {
//        Product product = new Product(){{setPrize(100)}};
//        XStream parser = Components.get(XStream.class, Product.class);
//        String xml = parser.toXML(product);
    }
    
}
